package com.meiyuetao.myt.md.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lab.s2jh.core.dao.BaseDao;
import lab.s2jh.core.service.BaseService;
import lab.s2jh.core.util.reflection.ReflectionUtils;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.hibernate.service.spi.ServiceException;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.google.common.collect.Lists;
import com.meiyuetao.myt.md.dao.CommodityDao;
import com.meiyuetao.myt.md.dao.CommodityPriceDao;
import com.meiyuetao.myt.md.entity.Commodity;
import com.meiyuetao.myt.md.entity.CommodityPrice;
import com.meiyuetao.myt.md.entity.CommodityPrice.CommodityPriceRuleTypeEnum;

@Service
@Transactional
public class CommodityPriceService extends BaseService<CommodityPrice, Long> {

    @Autowired
    private CommodityPriceDao commodityPriceDao;
    @Autowired
    private CommodityDao commodityDao;
    @Autowired
    private CommodityService commodityService;
    private BigDecimal divisionPrice = new BigDecimal(500);
    private Double divisionPriceRate = 0.4;
    private Map<String, Double> map = new HashMap<String, Double>() {
        {
            put("12", 0.75);
            put("13", 0.6);
            put("15", 0.4);
            put("50", 0.4);
            put("60", 0.4);
            put("10", 0.5);
            put("11", 0.5);
            put("14", 0.5);
            put("16", 0.5);
            put("20", 0.5);
            put("30", 0.5);
            put("40", 0.5);
        }
    };

    @Override
    protected BaseDao<CommodityPrice, Long> getEntityDao() {
        return commodityPriceDao;
    }

    // 设置最低价
    public void setupLineLowestPrice(CommodityPrice commodityPrice) {
        BigDecimal lowestPrice = commodityPrice.getM0Price();
        for (int idx = 1; idx <= 11; idx++) {
            Method getMethod = MethodUtils.getAccessibleMethod(commodityPrice.getClass(), "getM" + idx + "Price", new Class[] {});
            try {
                BigDecimal curPrice = (BigDecimal) getMethod.invoke(commodityPrice);
                if (curPrice != null && (lowestPrice == null || curPrice.compareTo(lowestPrice) < 0)) {
                    lowestPrice = curPrice;
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        commodityPrice.setLowestPrice(lowestPrice);
    }

    public List<CommodityPrice> calcCommodityPricesByGrade(DateTime startDate, DateTime endDate, BigDecimal basePrice, BigDecimal lowestPrice, Integer decreaseMonths) {
        try {
            Class<CommodityPrice> entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
            List<CommodityPrice> commodityPrices = Lists.newArrayList();
            Period period = new Period(startDate, endDate, PeriodType.months());
            int months = period.getMonths();
            for (int i = 0; i <= months; i++) {
                CommodityPrice commodityPrice = entityClass.newInstance();
                commodityPrices.add(commodityPrice);
                commodityPrice.setLowestPrice(lowestPrice);
                commodityPrice.setRuleType(CommodityPriceRuleTypeEnum.DECREASE_BY_GRADE.name());
                commodityPrice.setPriceYear(startDate.plusMonths(i).getYear());
                commodityPrice.setPriceMonth(startDate.plusMonths(i).getMonthOfYear());
                DateTime priceTime = new DateTime(commodityPrice.getPriceYear(), commodityPrice.getPriceMonth(), 1, 0, 0);
                commodityPrice.setPriceTime(priceTime.toDate());
                // 爬虫导入草稿商品，价格计划最后一个月设置默认
                if (i == months) {
                    commodityPrice.setDefaultPrice(Boolean.TRUE);
                } else {
                    commodityPrice.setDefaultPrice(Boolean.FALSE);
                }
                for (int j = 0; j <= decreaseMonths; j++) {
                    if (j == 0) {
                        commodityPrice.setM0Price(basePrice);
                    } else if (j <= 11) {
                        setGradePrice(commodityPrice, basePrice, decreaseMonths, lowestPrice, j);
                    }
                }
            }
            return commodityPrices;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    private void setGradePrice(CommodityPrice commodityPrice, BigDecimal basePrice, Integer decreaseMonths, BigDecimal lowestPrice, int idx) throws Exception {
        Assert.isTrue(idx > 0 && idx <= 11);
        Method setMethod = MethodUtils.getAccessibleMethod(commodityPrice.getClass(), "setM" + idx + "Price", new Class[] { BigDecimal.class });
        BigDecimal decrease = basePrice.subtract(lowestPrice).divide(new BigDecimal(decreaseMonths), 3, BigDecimal.ROUND_HALF_EVEN);
        BigDecimal price;
        if (idx == decreaseMonths) {
            price = lowestPrice;
        } else {
            price = basePrice.subtract(decrease.multiply(new BigDecimal(idx))).setScale(1, BigDecimal.ROUND_HALF_EVEN);
        }
        if (lowestPrice != null) {
            if (price.compareTo(lowestPrice) < 0) {
                setMethod.invoke(commodityPrice, lowestPrice);
            } else {
                setMethod.invoke(commodityPrice, price);
            }

        } else {
            setMethod.invoke(commodityPrice, price);
        }
    }

    public String setOrCancelDefault(CommodityPrice bindingEntity) {
        Boolean flag = BooleanUtils.toBoolean(bindingEntity.getDefaultPrice());
        if (flag) {
            bindingEntity.setDefaultPrice(false);
            commodityPriceDao.save(bindingEntity);
            return "取消默认成功";
        } else {
            Commodity commodity = bindingEntity.getCommodity();
            for (CommodityPrice item : commodity.getCommodityPrices()) {
                if (BooleanUtils.toBoolean(item.getDefaultPrice())) {
                    item.setDefaultPrice(Boolean.FALSE);
                    commodityPriceDao.save(item);
                }

            }
            bindingEntity.setDefaultPrice(Boolean.TRUE);
            commodityPriceDao.save(bindingEntity);
            return "设置默认成功";
        }

    }

    public void doBatchLine(String defaultPriceStrategy, String ruleType, Long commoditySid, List<CommodityPrice> commodityPrices) {
        List<CommodityPrice> existsCommodityPrices = commodityPriceDao.findByCommodity(commodityDao.findOne(commoditySid));
        DateTime now = new DateTime(new DateTime().getYear(), new DateTime().getMonthOfYear(), 1, 0, 0);
        for (CommodityPrice commodityPrice : commodityPrices) {
            Date commPriceTime = new DateTime(commodityPrice.getPriceYear(), commodityPrice.getPriceMonth(), 1, 0, 0).toDate();

            if (commPriceTime.before(now.toDate())) {
                throw new ServiceException("不能创建或修改已过期的价格计划");

            }

            Boolean isExists = false;
            for (CommodityPrice existsCommodityPrice : existsCommodityPrices) {
                if (commodityPrice.getPriceYear().equals(existsCommodityPrice.getPriceYear()) && commodityPrice.getPriceMonth().equals(existsCommodityPrice.getPriceMonth())) {
                    isExists = true;
                    existsCommodityPrice.setM0Price(commodityPrice.getM0Price());
                    existsCommodityPrice.setM1Price(commodityPrice.getM1Price());
                    existsCommodityPrice.setM2Price(commodityPrice.getM2Price());
                    existsCommodityPrice.setM3Price(commodityPrice.getM3Price());
                    existsCommodityPrice.setM4Price(commodityPrice.getM4Price());
                    existsCommodityPrice.setM5Price(commodityPrice.getM5Price());
                    existsCommodityPrice.setM6Price(commodityPrice.getM6Price());
                    existsCommodityPrice.setM7Price(commodityPrice.getM7Price());
                    existsCommodityPrice.setM8Price(commodityPrice.getM8Price());
                    existsCommodityPrice.setM9Price(commodityPrice.getM9Price());
                    existsCommodityPrice.setM10Price(commodityPrice.getM10Price());
                    existsCommodityPrice.setM11Price(commodityPrice.getM11Price());
                    existsCommodityPrice.setCommoditySid(commoditySid);
                    existsCommodityPrice.setRuleType(ruleType);
                    setupLineLowestPrice(existsCommodityPrice);
                    super.save(existsCommodityPrice);
                    break;
                }
            }

            if (!isExists) {
                commodityPrice.setCommoditySid(commoditySid);
                Date priceTime = new DateTime(commodityPrice.getPriceYear(), commodityPrice.getPriceMonth(), 1, 0, 0).toDate();
                commodityPrice.setPriceTime(priceTime);
                commodityPrice.setRuleType(ruleType);

                setupLineLowestPrice(commodityPrice);
                save(commodityPrice);
            }
        }
        // 找出最后一个月的价格计划

        CommodityPrice commodityPricelastMonth = null;
        // DateTime dateTime = new DateTime();
        for (CommodityPrice commodityPrice : existsCommodityPrices) {
            if (commodityPricelastMonth == null || commodityPricelastMonth.getPriceTime().before(commodityPrice.getPriceTime())) {
                commodityPricelastMonth = commodityPrice;
            }

        }

        CommodityPrice commodityPriceDefault = findDefaultPrice(commoditySid);
        if ("FORCE_LAST".equals(defaultPriceStrategy)) {
            if (commodityPriceDefault != null) {
                commodityPriceDefault.setDefaultPrice(Boolean.FALSE);
                this.save(commodityPriceDefault);

            }
            commodityPricelastMonth.setDefaultPrice(Boolean.TRUE);
            this.save(commodityPricelastMonth);

        } else if ("LAST_IF_UNSET".equals(defaultPriceStrategy)) {
            if (commodityPriceDefault == null) {
                commodityPricelastMonth.setDefaultPrice(Boolean.TRUE);
                this.save(commodityPricelastMonth);
            }
        }
        // 更新商品价格
        if (commodityPricelastMonth instanceof CommodityPrice) {
            Commodity commodity = commodityDao.findOne(commoditySid);
            commodityService.updatePriceByCommodityPrice(commodity);
        }

    }

    public CommodityPrice findDefaultPrice(Long commoditySid) {
        List<CommodityPrice> commodityPrices = commodityPriceDao.findByCommodity(commodityDao.findOne(commoditySid));
        for (CommodityPrice commodityPrice : commodityPrices) {
            if (commodityPrice.getDefaultPrice() == Boolean.TRUE) {
                return commodityPrice;
            }
        }
        return null;
    }

    @Override
    public CommodityPrice save(CommodityPrice entity) {
        setupLineLowestPrice(entity);
        return super.save(entity);
    }

    public BigDecimal calcLowestPrice(Commodity commodity) {
        BigDecimal basePrice = commodity.getPrice();
        Assert.isTrue(basePrice != null && basePrice.compareTo(BigDecimal.ZERO) != 0, "基准价不能为空或0");
        BigDecimal lowestPrice = null;
        String categoryCode = commodity.getCategory() == null ? null : commodity.getCategory().getCategoryCode();
        if (basePrice.compareTo(divisionPrice) >= 0) {
            lowestPrice = basePrice.multiply(new BigDecimal(divisionPriceRate)).setScale(1, BigDecimal.ROUND_HALF_EVEN);
        }
        if (StringUtils.isNotBlank(categoryCode) && basePrice.compareTo(divisionPrice) < 0) {
            Double rate = map.get(categoryCode.substring(0, 2));
            if (rate != null) {
                lowestPrice = basePrice.multiply(new BigDecimal(rate)).setScale(1, BigDecimal.ROUND_HALF_EVEN);
            }
        } else {
            lowestPrice = basePrice;
        }
        return lowestPrice;
    }

}
